<?php

if (!defined('IN_TG')) {
    exit('Access decline');
}

/**
 * 链接mysql数据库类
 * 使用方式：$dbconn = new DbMysql();   $result = $dbconn->sql_fetch_assoc("SELECT....");
 */

// 建立对象类
class DbMysql
{
    private $dbHost = "localhost"; //定义默认连接方式
    private $dbUser = "root"; //定义默认用户名
    private $dbPwd = "dreamren"; //定义默认的密码
    private $dbName = "baoduoduo_mini_expo"; //定义默认的数据库名
    private $conn;

    //构造方法，用来初始化数据，链接数据库
    public function __construct()
    {
        $this->con_mysql();
    }

    /**
     * 连接数据库资句柄
     */
    private function con_mysql()
    {
        //造一个连接对象，参数是上面的那四个
        @$this->conn = new mysqli($this->dbHost, $this->dbUser, $this->dbPwd, $this->dbName, 3306);
        if (mysqli_connect_errno()) {
            echo 'database open fail: ' . mysqli_connect_error();
            exit();
        }
        $this->conn->set_charset('utf8');
        //echo 'success';
    }

    /**
     * getQuery 返回SQL语句的结果集
     * @param string $sql sql语句
     * @return object 查询成功后返回mysqli_result对象(结果集)，可以使用$dbconn->res_fetch_assoc($result)取得一行作为关联数组
     */
    private function getQuery($sql)
    {
        // 判断SQL语句为空就终止程序
        if (empty($sql)) {
            exit('SQL语句不能为空');
        }
        // 失败时返回 false
        // 通过mysqli_query() 成功执行SELECT, SHOW, DESCRIBE或 EXPLAIN查询会返回一个mysqli_result 对象
        // 其他查询(insert|delete|update等)则返回 true。
        $result = $this->conn->query($sql);
        if ($this->conn->errno > 0) {
            echo 'SQL语句出错 ' . $this->conn->errno;
            // echo $this->conn->error;
            exit;
        }
        // SELECT返回一个mysqli_result对象
        return $result;
    }

    /**
     * sql_query 返回SQL语句的结果集
     * @param string $sql sql语句
     * @return object 查询成功后返回mysqli_result对象(结果集)，可以使用$dbconn->res_fetch_assoc($result)取得一行作为关联数组
     */
    public function sql_query($sql)
    {
        return $this->getQuery($sql);
    }

    /**
     * sql_fetch_row 返回SQL语句的结果集，并从中取得一行作为枚举数组
     * @param string $sql sql语句
     * @return array 查询成功后返回mysqli_result对象(结果集)，在结果集中取得一行作为枚举数组
     */
    public function sql_fetch_row($sql)
    {
        $result = $this->getQuery($sql);
        return $result->fetch_row();
    }

    /**
     * sql_fetch_assoc 返回SQL语句的结果集，并从中取得一行作为关联数组
     * @param string $sql sql语句
     * @return array 查询成功后返回mysqli_result对象(结果集)，在结果集中取得一行作为关联数组
     */
    public function sql_fetch_assoc($sql)
    {
        // 判断SQL语句为空就终止程序
        if (empty($sql)) {
            exit('SQL语句不能为空');
        }
        if (!$result = $this->conn->query($sql)) {
            echo 'SQL语句出错 '. $this->conn->errno;
            // echo $this->conn->error;
            exit;
        }
        if ($this->conn->errno > 0) {
            echo 'SQL语句出错 ' . $this->conn->errno;
            // echo $this->conn->error;
            exit;
        }
        return $result->fetch_assoc();
    }

    /**
     * sql_fetch_array 返回SQL语句的结果集，并从中取得一行作为关联数组
     * @param string $sql sql语句
     * @return array 查询成功后返回mysqli_result对象(结果集)，在结果集中取得一行作为关联数组
     */
    public function sql_fetch_array($sql)
    {
        $result = $this->getQuery($sql);
        return $result->fetch_array();
        
    }

    /**
     * sql_fetch_all 返回SQL语句的结果集，取得所有行作为一个数组
     * @param string $sql sql语句
     * @return array 查询成功后返回mysqli_result对象(结果集)，在结果集中所有行作为一个数组
     */
    public function sql_fetch_all($sql)
    {
        $result = $this->getQuery($sql);
        return $result->fetch_all(MYSQLI_ASSOC); //查询语句，返回数组.执行sql的返回方式是all，也可以换成row
        
    }

    /**
     * sql_num_rows 返回SQL语句的结果集，并返回SQL结果集行数
     * @param string $sql sql语句
     * @return int 查询成功后，返回结果mysqli_result对象(集行数)，在取得结果集行数
     */
    public function sql_num_rows($sql)
    {
        $result = $this->getQuery($sql);
        // 失败时返回 false
        // 通过mysqli_query() 成功执行SELECT, SHOW, DESCRIBE或 EXPLAIN查询会返回一个mysqli_result 对象
        // 其他查询(insert|delete|update等)则返回 true。
        if ($result) {
            $num = $result->num_rows;
            return $num;
        } else {
            return 0;
        }
        
    }

    /**
     * sql_affected_rows 执行(添加|修改|删除)SQL语句，并返回结果集影响的行数
     * @param string $sql insert|update|delete 语句
     * @return int (添加|修改|删除)执行成功后，并返回影响的行数
     */
    public function sql_affected_rows($sql)
    {
        $result = $this->getQuery($sql);
        // 失败时返回 false
        // 通过mysqli_query() 成功执行SELECT, SHOW, DESCRIBE或 EXPLAIN查询会返回一个mysqli_result 对象
        // 其他查询(insert|delete|update等)则返回 true。
        if ($result == true) {
            $num = $this->conn->affected_rows;
            if ($num >= 1) {
                return $num;
            } else {
                return $num;
            }
        } else {
            return false;
        }
    }

    /**
     * res_fetch_assoc 从传入的结果集中，取得一行作为关联数组
     * @param mixed $result 传入的结果集
     * @return array 从传入的结果集中，取得行作为关联数组
     */
    public function res_fetch_assoc($result)
    {
        if (!$result) {
            exit('结果集出错');
        }
        return $result->fetch_assoc();
    }

    /**
     * res_num_rows 从传入的结果集中，取得结果集行数
     * @param mixed $result 传入的结果集
     * @return int 从传入的结果集行数
     */
    public function res_num_rows($result)
    {
        if (!$result) {
            exit('结果集出错');
        }
        return $result->num_rows;
    }


    /**
     * insertArr 以表所有字段名建立的数组，转换为INSERT语句，写入表中一行新的数据
     * @param array $arrayList 使用表所有字段名建立的数组。
     * @param string $dbTableName 要插入数据的表名
     * @return array 返回包含3元素的数组，arr[0]:影响的条数，arr[1]:添加的id，arr[3]:返回的文字信息
     */
    public function insertArr($arrayList, $dbTableName, $isshowsql = 0)
    {
        // 判断传入如果不是数组就终止程序。
        if (!is_array($arrayList)) {
            return array(0, 0, 'Illegal data submitted');
            // return '提交数据不合法';
        }
        // 判断表名为空就终止程序。
        if (empty($dbTableName)) {
            return array(0, 0, 'Illegal table name');
            // return '非法表名';
        }
        $table_key_str = ""; // 循环读出数组中的键名（数据表字段名: name,age,gender）
        $add_val_str = ""; // 循环读出数组中的键值（'dream',30,'男'）
        // 使用escapeSqlStr在数组中循环使用real_escape_string()转义在 SQL 语句中使用的字符串中的特殊字符。
        $arrayList = $this->escapeSqlStr($arrayList);
        // 获取数组中的键名，建立一个新数组
        $field_arr = array_keys($arrayList);
        // 获取数组中的键值，建立一个新数组
        $_cont_arr = array_values($arrayList);
        // 循环数组键名以逗号分割（生成insert语句VALUES前面的表字段名）
        foreach ($field_arr as $_key) {
            $table_key_str .= $_key . ", ";
        }
        // 循环数组键值以逗号分割（生成insert语句VALUES后面的表字段值）
        foreach ($_cont_arr as $_value) {
            if (!is_numeric($_value)) {
                $add_val_str .= "'" . $_value . "', ";
            } else {
                $add_val_str .= $_value . ", ";
            }
        }
        // 删除表字段名循环时的最后一个逗号
        $table_key_str = substr(trim($table_key_str), 0, -1);
        // 删除表字段值循环时的最后一个逗号
        $add_val_str = substr(trim($add_val_str), 0, -1);
        // 拼接成insert SQL语句
        $sql_str = "INSERT INTO " . $dbTableName . " ( " . $table_key_str . " ) VALUES ( " . $add_val_str . " )";
        if ($isshowsql) {
            echo $sql_str;
        }
        // 使用mysqli的query()对数据库执行一次查询
        $result = $this->getQuery($sql_str);
        // 失败时返回 false
        // 通过mysqli_query() 成功执行SELECT, SHOW, DESCRIBE或 EXPLAIN查询会返回一个mysqli_result 对象
        // 其他查询(insert|delete|update等)则返回 true。
        if ($result == true) {
            // 获取添加成功影响的行数
            $aff_num = $this->conn->affected_rows;
            // 获取添加成功最新的id
            $newID = $this->conn->insert_id;
            if ($aff_num >= 1) {
                // 如果影响的行数大于0，就表示添加成功了
                return array($aff_num, $newID, 'Added successfu');
            } else {
                // 没有记录被添加
                return array(0, 0, 'No records added');
            }
        } else {
            // 如果$result 没有返回true，就说明添加失败了。（字段名不对，或字段值不符合等）
            return array(0, 0, 'Add failed');
        }
    }

    /**
     * upWhereArr 以指定表字段名建立的数组，转换为UPDATE语句，修改表中符合where条件的数据行
     * @param array $arrayList 使用表所有字段名建立的数组。
     * @param string $dbTableName 要插入数据的表名
     * @parma string $sqlWhere 执行UPDATE语句必须要指定的where条件
     * @return array 返回包含2元素的数组，arr[0]:影响的条数，arr[1]:返回的文字信息
     */
    public function upWhereArr($arrayList, $dbTableName, $sqlWhere, $isshowsql=0)
    {
        // 判断传入如果不是数组就终止程序。
        if (!is_array($arrayList)) {
            return array(0, 'Illegal data submitted');
            // return '提交数据不合法';
        }
        // 判断表名为空就终止程序。
        if (empty($dbTableName)) {
            return array(0, 0, 'Illegal table name');
            // return '非法表名';
        }
        // 判断where条件为空就终止程序。
        if (empty($sqlWhere)) {
            return array(0, 0, 'Illegal where');
            // return 'where条件不能空间';
        }
        $mod_val_str = ""; // 对要修改的数据值，字符串加上单引号，数值不加单引号（20 | 'dream'）
        $_set_val =""; // key=value的字符串（ age=20, name='dream' ）
        // 使用escapeSqlStr在数组中循环使用real_escape_string()转义在 SQL 语句中使用的字符串中的特殊字符。
        $arrayList = $this->escapeSqlStr($arrayList);
        foreach ($arrayList as $_key => $_value) {
            // 对更新的值，字符串加上单引号，数值不加单引号（20 | 'dream'）
            if (!is_numeric($_value)) {
                $mod_val_str = "'" . $_value . "', ";
            } else {
                $mod_val_str = $_value . ", ";
            }
            // 将字段名=字段值
            $_set_val .= $_key . ' = ' . $mod_val_str;
        }
        // 删除循环的最后一个逗号
        $_set_val = substr(trim($_set_val), 0, -1);
        // 拼接成UPDATE SET WHERE 格式的SQL语句
        $sql_str = "UPDATE " . $dbTableName . " SET " . $_set_val . " WHERE " . $sqlWhere . " ";
        if ($isshowsql) {
            echo $sql_str;
        }
        // 使用mysqli的query()对数据库执行一次查询
        $result = $this->getQuery($sql_str);
        // 失败时返回 false
        // 通过mysqli_query() 成功执行SELECT, SHOW, DESCRIBE或 EXPLAIN查询会返回一个mysqli_result 对象
        // 其他查询(insert|delete|update等)则返回 true。
        if ($result == true) {
            // 获取更新成功影响的行数
            $aff_num = $this->conn->affected_rows;
            if ($aff_num >= 1) {
                // 如果影响的行数大于0，就表示更新成功了
                return array($aff_num, 'modifyed successfu');
            } else {
                // 没有记录被更新
                return array(0, 'No records modifyed');
            }
        } else {
            // 更新失败
            return array(0, 'modify failed');
        }
    }

    /**
     * addOperateRecord 添加一条操作记录
     * @param int $tableType  数据库表类型(1后台管理员库，2文章库)
     * @param int $operateType  操作类型(1添加，2修改，3放入回收站，4从回收站中恢复，5彻底删除...)
     * @param int $info_id  操作主体id号
     * @param int $affectRows  操作影响条数
     * @param string $itemDescription  操作描述（500字以内）
     * @param int $userCategory  用户类别(1后台管理员，2访客，3注册用户...)
     * @param string $userIdentify  操作用户名（识别码）
     * @return null 成功不返回任何信息，失败时终止程序运行并提示：添加记录失败
     */
    public function addOperateRecord($tableType, $operateType, $info_id, $affectRows, $itemDescription, $userCategory, $userIdentify)
    {
        //检查getip()函数是否存在
        if (!function_exists('getip')) {
            exit('getip()函数不存在，请检查');
        }
        $_newarr = array();
        $_newarr['table_type'] = $tableType;
        $_newarr['operate_type'] = $operateType;
        $_newarr['info_id'] = $info_id;
        $_newarr['affect_rows'] = $affectRows;
        $_newarr['item_description'] = $itemDescription;
        $_newarr['user_category'] = $userCategory;
        $_newarr['user_identify'] = $userIdentify;
        $_newarr['add_time'] = date('Y-m-d H:i:s');
        $_newarr['add_ip'] = getip();
        // 查询ip对应地区
        $ips = new IPtoRegion();
        $_newarr['IPtoCitySelf'] = $ips->show($_newarr['add_ip'], 2);
        // ip对应地区结束
        $_newarr['isdeleted'] = 0;
        //过滤$_newarr数组
        $_newarr = $this->escapeSqlStr($_newarr);
        //插入数据，返回$_res['0']是插入条数，$_res['1']是成功后的id，$_res['2']是返回说明文字。
        $_res = $this->insertArr($_newarr, "_log_record_library");
        if ($_res[0] > 0 && $_res[1] > 0) {
            // 添加成功
        } else {
            exit('添加记录失败');
        }
    }


    /**
     * addLoginRecord 添加一条操作记录
     * @param int $userType  登录类型（1.管理员，2.用户）
     * @param string $loginName  登录帐号
     * @param int $isSuccess  是否登录成功，0为成功，1为失败
     * @param string $loginRemarks  登录说明
     * @return null 成功不返回任何信息，失败时终止程序运行并提示：添加记录失败
     */
    public function addLoginRecord($userType, $loginName, $isSuccess, $loginRemarks)
    {
        //检查getip()函数是否存在
        if (!function_exists('getip')) {
            exit('getip()函数不存在，请检查');
        }
        //检查getOS()函数是否存在
        if (!function_exists('getOS')) {
            exit('getOS()函数不存在，请检查');
        }
        $_newarr = array();
        $_newarr['user_type'] = $userType;
        $_newarr['login_name'] = $loginName;
        $_newarr['is_success'] = $isSuccess;
        $_newarr['login_remarks'] = $loginRemarks;
        $_newarr['login_os_sys'] = getOS(0); // 用户使用操作系统
        $_newarr['login_ip'] = getip();
        // 查询ip对应地区
        $ips = new IPtoRegion();
        $_newarr['IPtoCitySelf'] = $ips->show($_newarr['login_ip'], 2);
        // ip对应地区结束
        $_newarr['login_time'] = date('Y-m-d H:i:s');
        $_newarr['login_ismobile'] = isMobile(); // 是否是手机
        // User Agent中文名为用户代理，是Http协议中的一部分，属于头域的组成部分，User Agent也简称UA。它是一个特殊字符串头，是一种向访问网站提供你所使用的浏览器类型及版本、操作系统及版本、浏览器内核、等信息的标识。通过这个标识，用户所访问的网站可以显示不同的排版从而为用户提供更好的体验或者进行信息统计；例如用手机访问谷歌和电脑访问是不一样的，这些是谷歌根据访问者的UA来判断的。UA可以进行伪装。 浏览器的UA字串的标准格式：浏览器标识 (操作系统标识; 加密等级标识; 浏览器语言) 渲染引擎标识版本信息。但各个浏览器有所不同。
        $_newarr['login_user_agent'] = $_SERVER['HTTP_USER_AGENT'];
        // Accept请求的 HTTP 标头通告了内容类型，并表示为 MIME 类型
        $_newarr['login_accept'] = $_SERVER['HTTP_ACCEPT'];
        //过滤$_newarr数组
        $_newarr = $this->escapeSqlStr($_newarr);
        //插入数据，返回$_res['0']是插入条数，$_res['1']是成功后的id，$_res['2']是返回说明文字。
        $_res = $this->insertArr($_newarr, "_signin_record_lists");
        if ($_res[0] > 0 && $_res[1] > 0) {
            // 添加成功
        } else {
            exit('添加记录失败');
        }
    }

    /**
     * escapeSqlStr 对字符串或数组使用real_escape_string()转义在 SQL 语句中使用的字符串中的特殊字符
     * @param string|array $str 要转义在SQL中使用的字符串或数组
     * @return string|array 转义后在SQL中使用的字符串或数组
     */
    public function escapeSqlStr($str)
    {
        // 如果是数组就循环数组并转义
        if (is_array($str)) {
            foreach ($str as $_key => $_value) {
                //采用递归方式，执行函数自己
                $str[$_key] = $this->escapeSqlStr($_value);
            }
        } else {
            // 如果是字符串，执行real_escape_string来转义在SQL中使用的字符串
            //$str = mysqli_real_escape_string($this->conn, $str);
            $str = $this->conn->real_escape_string($str);
        }
        return $str;
    }

    /**
     * dbClose 关闭先前打开的数据库连接
     * @return boolean 关闭成功时返回 true，失败时返回 false。
     */
    public function dbClose()
    {
        $result = $this->conn->close();
        if (!$result) {
            echo '关闭异常';
        }
        return $result;
    }



    /**
     * sql_multi_query 返回SQL语句的结果集，并从中取得一行作为关联数组
     * @param string $sql sql语句
     * @return array 查询成功后返回mysqli_result对象(结果集)，在结果集中取得一行作为关联数组
     */
    public function sql_multi_query($sql)
    {
        // 判断SQL语句为空就终止程序
        if (empty($sql)) {
            exit('SQL语句不能为空');
        }
        if (!$result = $this->conn->multi_query($sql)) {
            echo 'SQL语句出错 ' . $this->conn->errno;
            // echo $this->conn->error;
            exit;
        }
        if ($this->conn->errno > 0) {
            echo 'SQL语句出错 ' . $this->conn->errno;
            // echo $this->conn->error;
            exit;
        }
        return $result;
    }



    // public function _queryPre($sql, $quanzhui, $params1, $params2, $params) {
    // if ($stmt = $this->conn->prepare($sql)) {
    //         /* 对于参数占位符进行参数值绑定 */
    //         //$params = array($city);
    //         // $params1 = "Android10";
    //         // $params2 = 2;
    //         // $params2 = array("Bob", "Johnson");
    //     $stmt->bind_param($quanzhui, $params1, $params2);
    //     /* 执行查询 */
    //     $stmt->execute();
    //         //$ro = $stmt->affected_rows;
    //         /* 将查询结果绑定到变量 */
    //         $result = $stmt->get_result();
    //     // /* 获取查询结果值 */
    //     // $stmt->fetch();
    //     // return $aa;
    //     //printf("%s is in district %s\n", $city, $login_os_sys);
    //     /* 关于语句对象 */
    //     $stmt->close();
    //     return $result;
    //     }
    // }


}



// $dbconn = new DbMysql();
// print_r($dbconn->sql_query('SELECT * FROM newuser'));
// print_r($dbconn->sql_fetch_row('SELECT * FROM newuser'));
// print_r($dbconn->sql_fetch_assoc('SELECT * FROM newuser'));
// print_r($dbconn->query_FetchArray('SELECT * FROM newuser'));
// print_r($dbconn->sql_fetch_all('SELECT * FROM newuser'));

// print_r($result = $dbconn->conn->query('SELECT tg_username FROM tg_user'));
// echo '<br />';
// var_dump($result);

// print_r($dbconn->sql_query('SELECT tg_username,tg_uniqid FROM newuser WHERE id>=10 LIMIT 2'));

// echo '<br /><br />';
// $usr = $dbconn->sql_fetch_assoc('SELECT * FROM newuser WHERE id>=10 ORDER BY id ASC LIMIT 1');
// print_r($usr);
// echo '<br />';
// echo $usr['tg_username'];


// echo '<br /><br />';
// print_r($dbconn->sql_query('SELECT * FROM newuser WHERE id>=10'));

// echo '<br /><br />';
// echo $dbconn->sql_num_rows('SELECT id FROM newuser');

// echo '<br /><br />';
// echo $dbconn->queryDelNum('DELETE FROM newuser WHERE id>=20 and id<=25');

// echo '<br /><br />';
// echo $dbconn->sql_insert_rows('INSERT INTO newuser (tg_username, tg_uniqid, tg_password, tg_question, tg_answer, tg_email, tg_qq, tg_url, tg_sex, tg_face, tg_level, tg_reg_time, tg_last_time, IsDeleted) VALUES ("aaa", "bbb", "ccc", "ddd", "eee", "fff", "222", "s", "男", "../a/", 0, "2020-02-17 12:35:48", "2020-02-17 12:35:48", 0)');


// echo '<br /><br />';
// $_clean = array();
// $_clean['tg_username'] = rand(10000,99999);
// $_clean['tg_uniqid'] = "D' FE43";
// $_clean['tg_password'] = 'ababac';
// $_clean['tg_question'] = 'ababac';
// $_clean['tg_answer'] = 'ababac';
// $_clean['tg_email'] = 'ababac';
// $_clean['tg_qq'] = '123';
// $_clean['tg_url'] = 'ababac';
// $_clean['tg_sex'] = 'a';
// $_clean['tg_face'] = 'ababac';
// $_clean['tg_level'] = 0;
// $_clean['tg_reg_time'] = '2020-02-17 12:35:48';
// $_clean['tg_last_time'] = '2020-02-17 12:35:48';
// $_clean['IsDeleted'] = 0;
// $_clean = $dbconn->escapeSqlStr($_clean);
// echo $dbconn->insertArr($_clean,'newuser');

//$dbconn->dbClose();

?>